package cn.trigram.web;

import cn.trigram.feign.EchoService;
import com.alibaba.csp.sentinel.Entry;
import com.alibaba.csp.sentinel.SphU;
import com.alibaba.csp.sentinel.Tracer;
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.context.ContextUtil;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeException;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

/**
 * 降级断路的意义是不再发送请求
 */
@Slf4j
@RefreshScope
@Setter(onMethod_ = {@Autowired})
@RestController
@RequestMapping("/test/sentinel")
public class SentinelController {

  private LoadBalancerClient loadBalancerClient;

  private RestTemplate restTemplate;

  private EchoService echoService;

  @Setter
  @Value("${appName:app}")
  private String appName;

  @GetMapping("/usage01")
  public String usage01() {
    //使用 LoadBalanceClient 和 RestTemplate 结合的方式来访问
    ServiceInstance serviceInstance = loadBalancerClient.choose("nacos-service02");
    String url = String.format("http://%s:%s/echo/%s",
                               serviceInstance.getHost(),
                               serviceInstance.getPort(), appName
    );
    System.out.println("app-name:" + appName);
    /*不能再使用这个restTemplate请求绝对地址了*/
    return restTemplate.getForObject(url, String.class);
  }

  @GetMapping(value = "/usage02")
  public String usage02(String q) {

    if (StringUtils.isBlank(q)) {
      throw new IllegalArgumentException("参数q不能为空");
    }
    String url = String.format("http://nacos-service02/echo/%s", "sentinel usage02");
    return restTemplate.getForObject(url, String.class);
  }

  @GetMapping(value = "/usage03")
  @SentinelResource(value = "usage03", blockHandler = "usage03BlockHandler")
  public String usage03() {


    return "Sentinel usage03";
  }

  public String usage03BlockHandler(BlockException t) {

    log.error(t.getClass().getName() + ":" + t.getMessage());
    log.error("usage03 限流降级");
    return "usage03 限流降级";
  }

  @GetMapping(value = "/usage04")
  public String usage04(String q) {

    if (StringUtils.isBlank(q)) {
      throw new IllegalArgumentException("参数q不能为空");
    }
    return echoService.echo("sentinel usage04");
  }

  @GetMapping(value = "/usage06")
  public String usage06() {

    return echoService.errorEcho("sentinel usage06");
  }

  @GetMapping(value = "/usage05")
  public String sentinelApiProgram(String q) {

    String resourceName = "sentinel-api-usage05";
    ContextUtil.enter(resourceName, "sentinel-origin-service02");
    try (
        Entry entry = SphU.entry(resourceName);
    ) {
      if (StringUtils.isBlank(q)) {
        throw new DegradeException("参数q不能为空");
      }
      return "sentinel usage05";
    } catch (BlockException e) {
      log.error("sentinel usage05 限流降级 {}", e.getMessage());
      return "sentinel usage05 限流降级";
    } catch (Exception e) {
      Tracer.trace(e);
      return "sentinel usage05 出现其它异常：" + e.getMessage();
    } finally {
      ContextUtil.exit();
    }
  }

}
